#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "driver/gpio.h"
#include "iic_aht10.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#define AHT10_Delay_ms(time)       vTaskDelay(time / portTICK_RATE_MS)
#define AHT10_ADDRESS 0x70
#define AHT10_WRITE 0x70
#define AHT10_READ 0x71
#define AHT10_SCL       19
#define AHT10_SDA       18
/* Private define ------------------------------------------------------------*/
#define AHT10_SCL_H          gpio_set_level(AHT10_SCL,1)
#define AHT10_SCL_L          gpio_set_level(AHT10_SCL,0)
#define AHT10_SDA_H         gpio_set_level(AHT10_SDA,1)
#define AHT10_SDA_L         gpio_set_level(AHT10_SDA,0)
#define AHT10_READ_SDA      gpio_get_level(AHT10_SDA)
#define GPIO_INPUT_PIN_SEL  (1ULL<<AHT10_SDA)
#define GPIO_OUTPUT_PIN_SEL  ((1ULL<<AHT10_SCL) | (1ULL<<AHT10_SDA))
#define aht10_print_switch 0
uint16_t temp = 10,humi = 10;;//aht10采集的温度，原本想使用队列来传递温度数据给LVGL任务，但是队列无法定义
char Aht10_TempValue[] = "no value";
char Aht10_HumiValue[] = "no value";
static const char *TAG = "AHT10";
 void AHT10_SDA_OUT(void)
{
     //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}

 void AHT10_SDA_IN(void)
{
      //zero-initialize the config structure.
    gpio_config_t io_conf = {};
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_INPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}

//产生IIC起始信号
 void AHT10_IIC_Start(void)
{
  AHT10_SDA_OUT();     //sda线输出
  AHT10_SDA_H;        
  AHT10_SCL_H;
  AHT10_Delay_ms(4);
  AHT10_SDA_L;//START:when CLK is high,DATA change form high to low 
  AHT10_Delay_ms(4);
  AHT10_SCL_L;//钳住I2C总线，准备发送或接收数据 
}   
//产生IIC停止信号
 void AHT10_IIC_Stop(void)
{
  AHT10_SDA_OUT();//sda线输出
  AHT10_SCL_L;
  AHT10_SDA_L;//STOP:when CLK is high DATA change form low to high
  AHT10_Delay_ms(4);
  AHT10_SCL_H; 
  AHT10_SDA_H;//发送I2C总线结束信号
  AHT10_Delay_ms(4);                  
}
//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功
 uint8_t AHT10_IIC_Wait_Ack(void)
{
  uint8_t ucErrTime=0;
  AHT10_SDA_IN();      //SDA设置为输入  
  AHT10_SDA_H;
  AHT10_Delay_ms(1);     
  AHT10_SCL_H;
  AHT10_Delay_ms(1);   
  while(AHT10_READ_SDA)
  {
    ucErrTime++;
    if(ucErrTime>250)
    {
      AHT10_IIC_Stop();
      return 1;
    }
  }
  AHT10_SCL_L;//时钟输出0      
  return 0;  
} 
//产生ACK应答
 void AHT10_IIC_Ack(void)
{
  AHT10_SCL_L;
  AHT10_SDA_OUT();
  AHT10_SDA_L;
  AHT10_Delay_ms(2);
  AHT10_SCL_H;
  AHT10_Delay_ms(2);
  AHT10_SCL_L;
}
//不产生ACK应答        
 void AHT10_IIC_NAck(void)
{
  AHT10_SCL_L;
  AHT10_SDA_OUT();
  AHT10_SDA_H;
  AHT10_Delay_ms(2);
  AHT10_SCL_H;
  AHT10_Delay_ms(2);
  AHT10_SCL_L;
}                      
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答       
 void AHT10_IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
  AHT10_SDA_OUT();      
    AHT10_SCL_L;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        //IIC_SDA=(txd&0x80)>>7;
    if((txd&0x80)>>7)
      AHT10_SDA_H;
    else
      AHT10_SDA_L;
    txd<<=1;    
    AHT10_Delay_ms(2);   //对TEA5767这三个延时都是必须的
    AHT10_SCL_H;
    AHT10_Delay_ms(2); 
    AHT10_SCL_L;  
    AHT10_Delay_ms(2);
    }  
}       
//读1个字节，ack=1时，发送ACK，ack=0，发送nACK   
 uint8_t AHT10_IIC_Read_Byte(unsigned char ack)
{
  unsigned char i,receive=0;
  AHT10_SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
  {
      AHT10_SCL_L; 
      AHT10_Delay_ms(2);
      AHT10_SCL_H;//SCL每一个上升沿读取一次SDA电平
      receive<<=1;
      if(AHT10_READ_SDA)receive++;   
      AHT10_Delay_ms(1); 
    }          
    if (!ack)
        AHT10_IIC_NAck();//发送nACK
    else
        AHT10_IIC_Ack(); //发送ACK   
    return receive;
}



/**
brief 检查AHT10是否存在
param NONE
return 0存在  1不存在
*/
uint8_t AHT10Check(void)
{
  uint8_t ack=0;
  AHT10_IIC_Start();
  AHT10_IIC_Send_Byte(AHT10_ADDRESS);
  ack=AHT10_IIC_Wait_Ack();
  AHT10_IIC_Stop(); 
  return ack;
}

/**
brief AHT10软复位
param NONE
return NONE
*/
void AHT10Reset(void)
{
  AHT10_IIC_Start();
  AHT10_IIC_Send_Byte(AHT10_WRITE);
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Send_Byte(0xba);
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Stop(); 
}



/**
brief AHT10初始化函数
param NONE
return NONE
*/
void AHT10Init()
{
  AHT10_IIC_Start();
  AHT10_IIC_Send_Byte(AHT10_ADDRESS);
  AHT10_IIC_Send_Byte(0xe1); //初始化命令 
  AHT10_IIC_Send_Byte(0x08); //基本命令
  AHT10_IIC_Send_Byte(0x00);
  AHT10_IIC_Stop(); 
  AHT10_Delay_ms(40);//延时20ms让传感器稳定
}

/**
brief 检查AHT10读温湿度数据
param *temperature：需要读出的温度数据，uint16_t指针类型,精度范围+-0.3C
param *humidity：需要读出的湿度数据，uint16_t指针类型,精度范围+-2RH
return 1 读数据正常 0读数据失败
*/
uint8_t AHT10ReadData(uint16_t *temperature,uint16_t *humidity)
{
  uint8_t ack;
  uint32_t SRH=0,ST=0;
  uint8_t databuff[6];
  AHT10_IIC_Start();
  AHT10_IIC_Send_Byte(AHT10_WRITE);
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Send_Byte(0xac);//触发测量
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Send_Byte(0x33);//DATA0固定值
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Send_Byte(0x00);//DATA1固定值
  AHT10_IIC_Wait_Ack();
  AHT10_IIC_Stop();   
  AHT10_Delay_ms(80);//延时一会等待数据读出
  AHT10_IIC_Start();
  AHT10_IIC_Send_Byte(AHT10_READ);
  AHT10_IIC_Wait_Ack();
  ack=AHT10_IIC_Read_Byte(1);
  if((ack&0x40)==0)
  {
    databuff[0]=AHT10_IIC_Read_Byte(1);
    databuff[1]=AHT10_IIC_Read_Byte(1);
    databuff[2]=AHT10_IIC_Read_Byte(1);
    databuff[3]=AHT10_IIC_Read_Byte(1);
    databuff[4]=AHT10_IIC_Read_Byte(0);
    AHT10_IIC_Stop();
    SRH=(databuff[0]<<12)+(databuff[1]<<4)+(databuff[2]>>4);//对比数据格式思考为何要这么计算
    ST=((databuff[2]&0X0f)<<16)+(databuff[3]<<8)+(databuff[4]);
//    *humidity=(int)(SRH*100.0/1024/1024+0.5);//未放大
//    *temperature=((int)(ST*2000.0/1024/1024+0.5))/10.0-50;//未放大，不过返回值最好为float
    *humidity = SRH*1000/1024/1024;  //计算得到湿度值（放大了10倍,如果c1=523，表示现在湿度为52.3%）
    *temperature = ST *200*10/1024/1024-500;//计算得到温度值（放大了10倍，如果t1=245，表示现在温度为24.5℃）
    //为读取的数据更稳定，还可以使用平均值滤波或者窗口滤波，或者前面读取的值与后面的值相差不能太大。
    if (aht10_print_switch)
    {
      ESP_LOGI(TAG, "humidity: %d\n", *humidity);
      ESP_LOGI(TAG,"temperature: %d\n",*temperature);
    }

    return 1;
  }
  AHT10_IIC_Stop(); 
  return 0;
}

void iic_aht10_begin(void *pvParameter)
{
   
    while(1)
    {
        AHT10ReadData(&temp,&humi);
        itoa(temp,Aht10_TempValue,10);//*temp转为字符型传给http组件
        itoa(humi,Aht10_HumiValue,10);
        //printf("temp = %d,humi = %d\n",temp,h);
    
        vTaskDelay(pdMS_TO_TICKS(100)); 
    }
    vTaskDelete(NULL);
}